#pragma once
#include <iostream>
// #include "Log.hpp"
// #include "LockGuard.hpp"
#include "Epoller.hpp"
#include "Connection.hpp" //TcpServer以链接对象为基准处理
#include <unordered_map>  //管理fd与链接之间的对应关系
// 对于已经就绪的事件，由TcpServer来进行通知
// TcpServer提供对就绪事件的通知、链接对象的管理工作
using namespace std;
// 事件派发器
class Reactor
{
    const static int gnum = 64;

public:
    Reactor()
        : _isrunning(false)
    {
    }
    ~Reactor() {}
    // 添加链接
    // 添加listen sock 到 TcpServer中，TcpServer独立维护链接对象
    void AddConnection(int fd, uint32_t events, func_t recver, func_t sender, func_t excepter)
    {
        // 1.构建Connection对象
        // 定义链接对象
        Connection *conn = new Connection(fd);
        // 设置关心的事件
        conn->SetEvents(events);
        // 注册方法---listensockfd只关心读方法
        conn->Register(recver, sender, excepter);
        conn->SetSelf(this);

        // 2.向内核中设定对fd的关心
        _epoller.AddEvent(conn->Sockfd(), conn->Events());

        // 3.向_connections添加connection对象
        _connections.insert(make_pair(conn->Sockfd(), conn));
    }

    // 检测指定fd在_connections中有没有注册方法
    bool ConnectionIsExists(int sockfd)
    {
        // 直接在_connections中使用fd进行查找
        auto iter = _connections.find(sockfd);
        if (iter == _connections.end())
        {
            // 没找到
            return false;
        }
        return true;
    }

    // 对指定的fd设置事件集合
    void EnableReadWrite(int sockfd, bool readable, bool writeable)
    {
        uint32_t events = EPOLLET;
        // 要关心读事件
        if (readable == true)
        {
            events |= EPOLLIN;
        }
        // 要关心写事件
        if (writeable == true)
        {
            events |= EPOLLOUT;
        }
        // 如果此fd在map中注册了fd->链接的映射
        if (ConnectionIsExists(sockfd) == true)
        {
            // 修改新事件的关心到map中
            _connections[sockfd]->SetEvents(events);
            // 修改新事件的关心到epoll模型中
            _epoller.ModEvent(sockfd, events);
        }
    }

    void RemoveConnection(int sockfd)
    {
        // 首先检测此sockfd对应的信息有没有在此map中注册方法
        if (ConnectionIsExists(sockfd) == false)
        {
            // 没有注册方法
            return;
        }
        // 注册了方法
        // 删除epoll模型中的关心
        _epoller.DelEvent(sockfd);
        // 服务端也需要关闭sockfd
        _connections[sockfd]->Close();
        // 释放connection对象
        delete _connections[sockfd];
        // 删除kv信息
        _connections.erase(sockfd);
    }

    // 一次事件派发
    void LoopOnce(int timeout)
    {
        int n = _epoller.Wait(_revs, gnum, timeout); // 获取到n个事件已经就绪了
        // if (n < 0)
        // {
        //     LOG(DEBUG, "此次epoll_wait获取链接失败了\n");
        //     return;
        // }
        // if (n == 0)
        // {
        //     LOG(DEBUG, "此次epoll_wait获取链接超时了\n");
        //     return;
        // }
        // n>0
        for (int i = 0; i < n; i++)
        {
            // 拿到此fd事件的基本信息
            int sockfd = _revs[i].data.fd;      // 文件描述符
            uint32_t revents = _revs[i].events; // 事件集合

            // 根据具体的事件处理
            // 将众多类型的错误，都转换为读写，这样众多错误就转化为读写的错误了，这样可以统一将错误进行处理
            // 对方将链接关闭了
            if (revents & EPOLLHUP)
            {
                // 连接关闭，就让他去读写，这样，它读写也会出错。
                revents |= (EPOLLIN | EPOLLOUT);
            }
            // 错误
            if (revents & EPOLLERR)
            {
                revents |= (EPOLLIN | EPOLLOUT);
            }
            // 读事件
            if (revents & EPOLLIN)
            {
                if (ConnectionIsExists(sockfd) && (_connections[sockfd]->_recver != nullptr))
                {
                    _connections[sockfd]->_recver(_connections[sockfd]);
                }
            }
            // 写事件
            if (revents & EPOLLOUT)
            {
                // 如果读事件处理方案已被设置，就去调用这个处理方法
                // 方法存在且不为空
                if (ConnectionIsExists(sockfd) && (_connections[sockfd]->_sender != nullptr))
                {
                    _connections[sockfd]->_sender(_connections[sockfd]);
                }
            }
        }
    }

    // 事件派发核心函数-总控
    void Dispatcher()
    {
        _isrunning = true;
        int timeout = 3000;
        while (_isrunning)
        {
            // 派发一次事件
            LoopOnce(timeout);
            // 此处，可以处理其他事情
            // 每次派发一次事件之后就看一下map表
            Debug();
        }
        _isrunning = false;
    }
    // 查看此刻map中的fd和events事件集合
    void Debug()
    {
        cout << "-------------------------------------" << endl;
        for (auto &connection : _connections)
        {
            cout << "fd:" << connection.second->Sockfd() << ",";
            uint32_t events = connection.second->Events();
            if ((events & EPOLLIN > 0) && (events & EPOLLET > 0))
            {
                cout << "EPOLLIN | EPOLLET";
            }
            if ((events & EPOLLOUT > 0) && (events & EPOLLET > 0))
            {
                cout << "EPOLLOUT | EPOLLET";
            }
            cout << endl;
        }
        cout << "-------------------------------------" << endl;
    }

private:
    unordered_map<int, Connection *> _connections; // sockfd->&Connection
    struct epoll_event _revs[gnum];                // 就绪事件集合
    Epoller _epoller;                              // epoll模型对象
    bool _isrunning;
};